﻿using Roslyn.Compilers.CSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QInjection.Injector
{
    internal class Configuration
    {
        private static volatile Configuration instance;
        private static object syncRoot = new Object();

        private Configurator _configurator;

        internal Configuration()
        {
            _configurator = new Configurator();

            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.Body));
            _configurator.Add(Element.BinaryExpression, 
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.Condition));
            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.Expression));
            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.LeftMember));
            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.RightMember));
            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.WhenTrue));
            _configurator.Add(Element.BinaryExpression,
                new Tuple<Node, Branch>(Node.BinaryExpression, Branch.WhenFalse));

            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.Body));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.Condition));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.Expression));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.LeftMember));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.RightMember));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.WhenTrue));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PrefixUnaryExpression, Branch.WhenFalse));

            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.Body));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.Condition));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.Expression));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.LeftMember));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.RightMember));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.WhenTrue));
            _configurator.Add(Element.UnaryExpression,
                new Tuple<Node, Branch>(Node.PostfixUnaryExpression, Branch.WhenFalse));

            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.Body));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.Condition));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.Expression));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.LeftMember));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.RightMember));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.WhenTrue));
            _configurator.Add(Element.ConditionalExpression,
                new Tuple<Node, Branch>(Node.ConditionalExpression, Branch.WhenFalse));

            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.Body));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.Condition));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.Expression));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.LeftMember));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.RightMember));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.WhenTrue));
            _configurator.Add(Element.IdentifierName,
                new Tuple<Node, Branch>(Node.IdentifierName, Branch.WhenFalse));

            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.Body));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.Condition));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.Expression));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.LeftMember));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.RightMember));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.WhenTrue));
            _configurator.Add(Element.LiteralExpression,
                new Tuple<Node, Branch>(Node.LiteralExpression, Branch.WhenFalse));

            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.Body));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.Condition));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.Expression));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.LeftMember));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.RightMember));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.WhenTrue));
            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.InvocationExpression, Branch.WhenFalse));

            _configurator.Add(Element.InvocationExpression,
                new Tuple<Node, Branch>(Node.Argument, Branch.Argument));
            
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.Body));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.Condition));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.Expression));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.LeftMember));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.RightMember));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.WhenTrue));
            _configurator.Add(Element.MemberAccessExpression,
                new Tuple<Node, Branch>(Node.MemberAccessExpression, Branch.WhenFalse));

            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.Body));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.Condition));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.Expression));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.LeftMember));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.RightMember));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.WhenTrue));
            _configurator.Add(Element.ParenthesizedExpression,
                new Tuple<Node, Branch>(Node.ParenthesizedExpression, Branch.WhenFalse));
        }

        internal static Configuration Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new Configuration();
                    }
                }

                return instance;
            }
        }

        internal Configurator GetDefaultInstructor()
        {
            if (instance == null)
                throw new Exception("Singleton NodeToType not instanciated");
            return instance._configurator;
        }

    }
}
